package negocios;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

import negocios.excecoes.LocalizacaoException;

import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService;

/**
 * Classe que implementa uma estrategia de Localizacao, atraves do Banco de
 * Dados GeoIP. Se o IP for Local, o Localizador nao conseguira obter nenhuma
 * localizacao.
 * 
 * @author Jonathan Brilhante
 * @author Jose Rafael
 * @author Nata Venancio
 * @author Renato Almeida
 * 
 * @version 1.0
 */

public class LocalizadorIP implements Localizador {
	/**
	 * Constante do IP Local
	 */
	public static final String IP_LOCAL = "127.0.0.1";

	private static final char IP_SEP = '.';
	private static final int NUM_PONTOS = 3;
	private static final String SEP = System.getProperty("file.separator");
	private static final String DIR = System.getProperty("user.dir");
	private static final String DB = DIR + SEP + "db" + SEP + "GeoLiteCity.dat";

	private String userIp;
	private Location local;

	/**
	 * Constroi um LocalizadorIP a partir do IP da maquina.
	 * 
	 * @throws LocalizacaoException
	 *             caso nao seja valido este IP
	 * @throws UnknownHostException
	 *             caso nao seja possivel obte-lo automaticamente
	 */
	public LocalizadorIP() throws LocalizacaoException, UnknownHostException {
		this(InetAddress.getLocalHost().getHostAddress());
	}

	/**
	 * Construi um LocalizadorIP a partir do IP passado como parametro.
	 * 
	 * @param ip
	 *            o IP
	 * @throws LocalizacaoException
	 *             caso o IP seja invalido
	 */
	public LocalizadorIP(String ip) throws LocalizacaoException {
		if (!ipValido(ip)) {
			throw new LocalizacaoException("IP invalido.");
		}
		this.userIp = ip;
		if (!ip.equals(IP_LOCAL)) {
			LookupService centro = null;
			try {
				centro = new LookupService(DB, LookupService.GEOIP_MEMORY_CACHE
						| LookupService.GEOIP_CHECK_CACHE);
				if (centro.getLocation(userIp) == null) {
					throw new LocalizacaoException(
							"Nao foi possivel obter a localizacao.");
				}
				this.local = centro.getLocation(userIp);
			} catch (IOException e) {
				throw new LocalizacaoException(
						"Impossivel acessar o banco GeoIP");
			}
			centro.close();
		}
	}

	public Localizacao getLocalidade() throws LocalizacaoException {
		if (local == null) {
			throw new LocalizacaoException(
					"Nao foi possivel obter a localizacao.");
		}
		return new Localizacao(local.latitude, local.longitude,
				local.countryName, local.city);
	}

	/**
	 * Retorna o ip desse Localizador
	 * 
	 * @return o ip do Localizador
	 */
	public String getIp() {
		return userIp;
	}

	/**
	 * Responde se o IP passado como parametro e um ip valido (sua estrutura)
	 * 
	 * @param ip
	 *            o ip a ser avaliado
	 * @return true, se for valido, false, caso contrario
	 */
	private boolean ipValido(String ip) {
		if (ip == null) {
			return false;
		}
		int cont = 0;
		for (int i = 0; i < ip.length(); i++) {
			char letra = ip.charAt(i);
			if (letra == IP_SEP) {
				cont++;
			} else if (!Character.isDigit(letra)) {
				return false;
			}
		}
		if (cont != NUM_PONTOS) {
			return false;
		}
		return true;
	}
}